package com.joe.socket.Server;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.joe.socket.Model.ChatMessage;
import com.joe.socket.Model.UserSession;
import com.joe.socket.Dao.UserSessionDao;
import com.joe.socket.Dao.MessageHistoryDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Component
public class WebSocketServer implements WebSocketHandler {

    private static final Logger logger = LoggerFactory.getLogger(WebSocketServer.class);

    private final Map<String, WebSocketSession> sessions = new ConcurrentHashMap<>();
    private final ObjectMapper objectMapper = new ObjectMapper();

    @Autowired(required = false)
    private UserSessionDao userSessionDao;

    @Autowired(required = false)
    private MessageHistoryDao messageHistoryDao;

    public WebSocketServer() {
        startHeartbeatTask();
    }

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        String sessionId = session.getId();
        sessions.put(sessionId, session);

        logger.info("新的WebSocket连接建立: {}", sessionId);

        if (userSessionDao == null) {
            logger.error("UserSessionDao 注入失败!");
            sendErrorMessage(session, "服务器配置错误");
            session.close(CloseStatus.SERVER_ERROR);
            return;
        }

        // 创建临时用户会话
        UserSession tempSession = new UserSession();
        tempSession.setSessionId(sessionId);
        tempSession.setUsername("临时用户_" + sessionId.substring(0, 8));
        tempSession.setRemoteAddress(session.getRemoteAddress() != null ?
                session.getRemoteAddress().toString() : "unknown");
        tempSession.setActive(false);

        try {
            userSessionDao.saveSession(tempSession);
            logger.info("临时用户会话创建成功");
        } catch (Exception e) {
            logger.error("保存用户会话失败: {}", e.getMessage());
            sendErrorMessage(session, "服务器内部错误");
            session.close(CloseStatus.SERVER_ERROR);
            return;
        }

        // 发送连接成功消息
        sendWelcomeMessage(session);

        // 发送当前在线用户列表
        sendOnlineUsersListToSession(session);

        logger.info("等待用户发送JOIN消息...");
    }

    @Override
    public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
        if (!(message instanceof TextMessage)) {
            logger.warn("不支持的消息类型");
            return;
        }

        String payload = ((TextMessage) message).getPayload();
        String sessionId = session.getId();

        logger.info("收到消息 from {}: {}", sessionId, payload);

        try {
            ChatMessage chatMessage = objectMapper.readValue(payload, ChatMessage.class);
            chatMessage.setSessionId(sessionId);

            if (chatMessage.getType() == null) {
                sendErrorMessage(session, "消息类型不能为空");
                return;
            }

            processMessage(session, chatMessage);

        } catch (Exception e) {
            logger.error("消息处理错误: {}", e.getMessage(), e);
            sendErrorMessage(session, "消息格式错误: " + e.getMessage());
        }
    }

    private void processMessage(WebSocketSession session, ChatMessage message) throws IOException {
        try {
            switch (message.getType()) {
                case JOIN:
                    handleUserJoin(session, message);
                    break;
                case TEXT:
                    handleTextMessage(session, message);
                    break;
                case PRIVATE:
                    handlePrivateMessage(session, message);
                    break;
                case LEAVE:
                    handleUserLeave(session.getId());
                    break;
                case HEARTBEAT:
                    handleHeartbeat(session, message);
                    break;
                default:
                    logger.warn("未知的消息类型: {}", message.getType());
                    sendErrorMessage(session, "未知的消息类型: " + message.getType());
            }
        } catch (Exception e) {
            logger.error("处理消息时发生错误: {}", e.getMessage(), e);
            sendErrorMessage(session, "处理消息时发生错误");
        }
    }

    private void handleUserJoin(WebSocketSession session, ChatMessage message) throws IOException {
        String sessionId = session.getId();
        String username = message.getSender();

        logger.info("处理用户加入: sessionId={}, username={}", sessionId, username);

        if (username == null || username.trim().isEmpty()) {
            sendErrorMessage(session, "用户名不能为空");
            return;
        }

        username = username.trim();

        try {
            UserSession existingSession = userSessionDao.getSessionByUsername(username);
            if (existingSession != null && existingSession.isActive()) {
                String newUsername = username + "_" + sessionId.substring(0, 4);
                sendSystemMessage(session, "用户名已存在，已自动修改为: " + newUsername);
                username = newUsername;
            }

            UserSession userSession = userSessionDao.getSessionById(sessionId);
            if (userSession == null) {
                userSession = new UserSession();
                userSession.setSessionId(sessionId);
            }

            userSession.setUsername(username);
            userSession.setLoginTime(LocalDateTime.now());
            userSession.setActive(true);
            userSessionDao.saveSession(userSession);

            logger.info("用户加入成功: {}", username);

            sendSystemMessage(session, "欢迎 " + username + " 加入聊天室！");

            // 广播用户加入消息
            ChatMessage joinMessage = new ChatMessage();
            joinMessage.setType(ChatMessage.MessageType.SYSTEM);
            joinMessage.setContent(username + " 加入了聊天室");
            joinMessage.setSender("系统");
            joinMessage.setTimestamp(System.currentTimeMillis());

            if (messageHistoryDao != null) {
                messageHistoryDao.saveMessage(joinMessage);
            }

            broadcastMessage(joinMessage);

            // 发送历史消息给新用户
            sendHistoryMessages(session);

            // 发送在线用户数
            sendOnlineUserCount();

            // 广播更新后的用户列表
            sendOnlineUsersList();

        } catch (Exception e) {
            logger.error("处理用户加入时错误: {}", e.getMessage(), e);
            sendErrorMessage(session, "加入聊天室失败: " + e.getMessage());
        }
    }

    private void handleTextMessage(WebSocketSession session, ChatMessage message) throws IOException {
        String sessionId = session.getId();
        UserSession userSession = userSessionDao.getSessionById(sessionId);

        if (userSession == null || !userSession.isActive()) {
            sendErrorMessage(session, "请先发送JOIN消息加入聊天室");
            return;
        }

        // 设置发送者和时间戳
        message.setSender(userSession.getUsername());
        message.setTimestamp(System.currentTimeMillis());

        // 保存消息
        if (messageHistoryDao != null) {
            messageHistoryDao.saveMessage(message);
        }

        // 广播消息
        broadcastMessage(message);

        logger.info("广播消息 from {}: {}", userSession.getUsername(), message.getContent());
    }

    private void handlePrivateMessage(WebSocketSession session, ChatMessage message) throws IOException {
        sendErrorMessage(session, "私聊功能暂未实现");
    }

    private void handleHeartbeat(WebSocketSession session, ChatMessage message) throws IOException {
        ChatMessage pong = new ChatMessage();
        pong.setType(ChatMessage.MessageType.HEARTBEAT);
        pong.setContent("pong");
        pong.setSender("系统");
        pong.setTimestamp(System.currentTimeMillis());

        sendMessage(session, pong);
    }

    private void handleUserLeave(String sessionId) {
        try {
            UserSession userSession = userSessionDao.getSessionById(sessionId);
            if (userSession != null) {
                userSession.setActive(false);

                // 广播用户离开消息
                ChatMessage leaveMessage = new ChatMessage();
                leaveMessage.setType(ChatMessage.MessageType.SYSTEM);
                leaveMessage.setContent(userSession.getUsername() + " 离开了聊天室");
                leaveMessage.setSender("系统");
                leaveMessage.setTimestamp(System.currentTimeMillis());

                if (messageHistoryDao != null) {
                    messageHistoryDao.saveMessage(leaveMessage);
                }

                broadcastMessage(leaveMessage);

                // 发送更新后的在线用户数
                sendOnlineUserCount();

                // 广播更新后的用户列表
                sendOnlineUsersList();

                logger.info("用户离开: {}", userSession.getUsername());
            }
        } catch (Exception e) {
            logger.error("处理用户离开时错误: {}", e.getMessage());
        }
    }

    /**
     * 发送在线用户列表给所有客户端
     */
    private void sendOnlineUsersList() {
        try {
            List<UserSession> activeSessions = userSessionDao.getActiveSessions();
            List<String> onlineUsers = activeSessions.stream()
                    .map(UserSession::getUsername)
                    .collect(Collectors.toList());

            // 创建用户列表消息
            ChatMessage userListMessage = new ChatMessage();
            userListMessage.setType(ChatMessage.MessageType.SYSTEM);
            userListMessage.setContent("USER_LIST_UPDATE");
            userListMessage.setSender("系统");
            userListMessage.setTimestamp(System.currentTimeMillis());

            // 使用JSON格式发送用户列表
            String userListJson = objectMapper.writeValueAsString(onlineUsers);
            userListMessage.setContent(userListJson);

            broadcastMessage(userListMessage);

            logger.info("广播在线用户列表: {} 个用户", onlineUsers.size());

        } catch (Exception e) {
            logger.error("发送在线用户列表时出错: {}", e.getMessage());
        }
    }

    /**
     * 发送在线用户列表给指定客户端
     */
    private void sendOnlineUsersListToSession(WebSocketSession session) throws IOException {
        try {
            List<UserSession> activeSessions = userSessionDao.getActiveSessions();
            List<String> onlineUsers = activeSessions.stream()
                    .map(UserSession::getUsername)
                    .collect(Collectors.toList());

            ChatMessage userListMessage = new ChatMessage();
            userListMessage.setType(ChatMessage.MessageType.SYSTEM);
            userListMessage.setContent("USER_LIST_UPDATE");
            userListMessage.setSender("系统");
            userListMessage.setTimestamp(System.currentTimeMillis());

            String userListJson = objectMapper.writeValueAsString(onlineUsers);
            userListMessage.setContent(userListJson);

            sendMessage(session, userListMessage);

        } catch (Exception e) {
            logger.error("发送在线用户列表给会话时出错: {}", e.getMessage());
        }
    }

    private void broadcastMessage(ChatMessage message) {
        String jsonMessage;
        try {
            jsonMessage = objectMapper.writeValueAsString(message);
            logger.debug("广播消息: {}", jsonMessage);
        } catch (Exception e) {
            logger.error("消息序列化错误: {}", e.getMessage(), e);
            return;
        }

        TextMessage textMessage = new TextMessage(jsonMessage);
        sessions.forEach((sessionId, session) -> {
            if (session.isOpen()) {
                try {
                    session.sendMessage(textMessage);
                } catch (IOException e) {
                    logger.error("发送消息失败: {}", e.getMessage());
                }
            }
        });
    }

    private void sendMessage(WebSocketSession session, ChatMessage message) throws IOException {
        String jsonMessage = objectMapper.writeValueAsString(message);
        logger.debug("发送消息: {}", jsonMessage);
        session.sendMessage(new TextMessage(jsonMessage));
    }

    private void sendWelcomeMessage(WebSocketSession session) throws IOException {
        ChatMessage welcomeMsg = new ChatMessage();
        welcomeMsg.setType(ChatMessage.MessageType.SYSTEM);
        welcomeMsg.setContent("连接成功！请发送JOIN消息加入聊天室");
        welcomeMsg.setSender("系统");
        welcomeMsg.setTimestamp(System.currentTimeMillis());

        sendMessage(session, welcomeMsg);
    }

    private void sendSystemMessage(WebSocketSession session, String content) throws IOException {
        ChatMessage systemMsg = new ChatMessage();
        systemMsg.setType(ChatMessage.MessageType.SYSTEM);
        systemMsg.setContent(content);
        systemMsg.setSender("系统");
        systemMsg.setTimestamp(System.currentTimeMillis());

        sendMessage(session, systemMsg);
    }

    private void sendErrorMessage(WebSocketSession session, String error) throws IOException {
        ChatMessage errorMsg = new ChatMessage();
        errorMsg.setType(ChatMessage.MessageType.SYSTEM);
        errorMsg.setContent("错误: " + error);
        errorMsg.setSender("系统");
        errorMsg.setTimestamp(System.currentTimeMillis());

        sendMessage(session, errorMsg);
    }

    private void sendOnlineUserCount() {
        try {
            int activeUserCount = userSessionDao.getActiveUserCount();

            ChatMessage countMsg = new ChatMessage();
            countMsg.setType(ChatMessage.MessageType.SYSTEM);
            countMsg.setContent("当前在线用户数: " + activeUserCount);
            countMsg.setSender("系统");
            countMsg.setTimestamp(System.currentTimeMillis());

            broadcastMessage(countMsg);
        } catch (Exception e) {
            logger.error("发送在线用户数时错误: {}", e.getMessage());
        }
    }

    /**
     * 发送历史消息给新连接的用户
     */
    private void sendHistoryMessages(WebSocketSession session) throws IOException {
        if (messageHistoryDao == null) {
            logger.warn("MessageHistoryDao 未注入，无法发送历史消息");
            return;
        }

        try {
            // 获取最近50条历史消息
            List<ChatMessage> recentMessages = messageHistoryDao.getRecentMessages(50);

            if (recentMessages.isEmpty()) {
                logger.info("没有历史消息可发送");
                return;
            }

            logger.info("向用户 {} 发送 {} 条历史消息", session.getId(), recentMessages.size());

            // 发送历史消息标题
            ChatMessage historyHeader = new ChatMessage();
            historyHeader.setType(ChatMessage.MessageType.SYSTEM);
            historyHeader.setContent("--- 历史消息（最近" + recentMessages.size() + "条）---");
            historyHeader.setSender("系统");
            historyHeader.setTimestamp(System.currentTimeMillis());
            sendMessage(session, historyHeader);

            // 发送历史消息
            for (ChatMessage message : recentMessages) {
                sendMessage(session, message);
            }

            // 发送历史消息结束标记
            ChatMessage historyFooter = new ChatMessage();
            historyFooter.setType(ChatMessage.MessageType.SYSTEM);
            historyFooter.setContent("--- 历史消息结束 ---");
            historyFooter.setSender("系统");
            historyFooter.setTimestamp(System.currentTimeMillis());
            sendMessage(session, historyFooter);

        } catch (Exception e) {
            logger.error("发送历史消息时出错: {}", e.getMessage(), e);
            sendErrorMessage(session, "加载历史消息失败");
        }
    }

    private void startHeartbeatTask() {
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        scheduler.scheduleAtFixedRate(() -> {
            try {
                checkAndCleanInactiveSessions();
            } catch (Exception e) {
                logger.error("心跳检测任务执行异常: {}", e.getMessage());
            }
        }, 30, 30, TimeUnit.SECONDS);
    }

    private void checkAndCleanInactiveSessions() {
        logger.debug("执行心跳检测，当前活跃会话数: {}", sessions.size());

        sessions.entrySet().removeIf(entry -> {
            WebSocketSession session = entry.getValue();
            if (!session.isOpen()) {
                logger.info("清理非活跃会话: {}", entry.getKey());
                handleUserLeave(entry.getKey());
                return true;
            }
            return false;
        });
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        logger.error("WebSocket传输错误: {}", exception.getMessage(), exception);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
        String sessionId = session.getId();
        sessions.remove(sessionId);
        handleUserLeave(sessionId);

        logger.info("WebSocket连接关闭: {}, 状态: {}", sessionId, closeStatus.getCode());
    }

    @Override
    public boolean supportsPartialMessages() {
        return false;
    }

    /**
     * 获取服务器统计信息
     */
    public Map<String, Object> getServerStats() {
        Map<String, Object> stats = new HashMap<>();
        try {
            stats.put("activeConnections", sessions.size());
            stats.put("activeUsers", userSessionDao != null ? userSessionDao.getActiveUserCount() : 0);
            stats.put("totalMessages", messageHistoryDao != null ? messageHistoryDao.getMessageCount() : 0);
            stats.put("serverStartTime", System.currentTimeMillis());
            stats.put("status", "RUNNING");
        } catch (Exception e) {
            logger.error("获取服务器统计信息失败: {}", e.getMessage());
            stats.put("error", "获取统计信息失败: " + e.getMessage());
        }
        return stats;
    }

    /**
     * 获取在线用户列表
     */
    public List<String> getOnlineUsers() {
        try {
            if (userSessionDao != null) {
                return userSessionDao.getActiveSessions().stream()
                        .map(UserSession::getUsername)
                        .collect(Collectors.toList());
            }
        } catch (Exception e) {
            logger.error("获取在线用户列表失败: {}", e.getMessage());
        }
        return new ArrayList<>();
    }

    /**
     * 获取最近消息
     */
    public List<ChatMessage> getRecentMessages(int count) {
        try {
            if (messageHistoryDao != null) {
                return messageHistoryDao.getRecentMessages(count);
            }
        } catch (Exception e) {
            logger.error("获取最近消息失败: {}", e.getMessage());
        }
        return new ArrayList<>();
    }
}